#pragma once

#include "MultiplicityElement.h"

#include "ValueSpecification.h"

namespace uml {

const bool MultiplicityElement::isOrdered_default_ = false;
const bool MultiplicityElement::isUnique_default_ = true;
const int MultiplicityElement::lower_default_ = 0;
const int MultiplicityElement::upper_default_ = 0;
void MultiplicityElement::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    PartialElement::fromJson(json, errorList);
    isOrdered_ = json.value("isOrdered").toBool(isOrdered_default_);
    isUnique_ = json.value("isUnique").toBool(isUnique_default_);
    lower_ = json.value("lower").toInt(lower_default_);
    lowerValue_ = JsonSerializable::create<ValueSpecification>(json.value("lowerValue"), errorList);

    upper_ = json.value("upper").toInt(upper_default_);
    upperValue_ = JsonSerializable::create<ValueSpecification>(json.value("upperValue"), errorList);

}

void MultiplicityElement::toJson(QJsonObject& json) {
    PartialElement::toJson(json);
    if (isOrdered_ != isOrdered_default_) {
        json.insert("isOrdered", isOrdered_);
    }
    if (isUnique_ != isUnique_default_) {
        json.insert("isUnique", isUnique_);
    }
    if (lower_ != lower_default_) {
        json.insert("lower", lower_);
    }
    if (lowerValue_) {
        QJsonObject lowerValue_json;
        lowerValue_->toJson(lowerValue_json);
        json.insert("lowerValue", lowerValue_json);
    }
    if (upper_ != upper_default_) {
        json.insert("upper", upper_);
    }
    if (upperValue_) {
        QJsonObject upperValue_json;
        upperValue_->toJson(upperValue_json);
        json.insert("upperValue", upperValue_json);
    }
}

/// <summary>
/// compatibleWith
    /// The operation compatibleWith takes another multiplicity as input. It returns
    /// true if the other multiplicity is wider than, or the same as, self.
/// </summary>
    /// <code>
    /// result = ((other.lowerBound() <= self.lowerBound()) and ((other.upperBound() = *) or (self.upperBound() <= other.upperBound())))
    /// </code>
bool MultiplicityElement::compatibleWith(shared_ptr<MultiplicityElement> other) const
{
    return false;
}

/// <summary>
/// includesMultiplicity
    /// The query includesMultiplicity() checks whether this multiplicity includes all
    /// the cardinalities allowed by the specified multiplicity.
/// </summary>
    /// <code>
    /// self.upperBound()->notEmpty() and self.lowerBound()->notEmpty() and M.upperBound()->notEmpty() and M.lowerBound()->notEmpty()
    /// </code>
    /// <code>
    /// result = ((self.lowerBound() <= M.lowerBound()) and (self.upperBound() >= M.upperBound()))
    /// </code>
bool MultiplicityElement::includesMultiplicity(shared_ptr<MultiplicityElement> M) const
{
    return false;
}

/// <summary>
/// is
    /// The operation is determines if the upper and lower bound of the ranges are the
    /// ones given.
/// </summary>
    /// <code>
    /// result = (lowerbound = self.lowerBound() and upperbound = self.upperBound())
    /// </code>
bool MultiplicityElement::is(int lowerbound, int upperbound) const
{
    return false;
}

/// <summary>
/// isMultivalued
    /// The query isMultivalued() checks whether this multiplicity has an upper bound
    /// greater than one.
/// </summary>
    /// <code>
    /// upperBound()->notEmpty()
    /// </code>
    /// <code>
    /// result = (upperBound() > 1)
    /// </code>
bool MultiplicityElement::isMultivalued() const
{
    return false;
}

/// <summary>
/// lowerBound
    /// The query lowerBound() returns the lower bound of the multiplicity as an
    /// integer, which is the integerValue of lowerValue, if this is given, and 1
    /// otherwise.
/// </summary>
    /// <code>
    /// result = (if (lowerValue=null or lowerValue.integerValue()=null) then 1 else lowerValue.integerValue() endif)
    /// </code>
int MultiplicityElement::lowerBound() const
{
    return 0;
}

/// <summary>
/// upperBound
    /// The query upperBound() returns the upper bound of the multiplicity for a bounded
    /// multiplicity as an unlimited natural, which is the unlimitedNaturalValue of
    /// upperValue, if given, and 1, otherwise.
/// </summary>
    /// <code>
    /// result = (if (upperValue=null or upperValue.unlimitedValue()=null) then 1 else upperValue.unlimitedValue() endif)
    /// </code>
int MultiplicityElement::upperBound() const
{
    return 0;
}

/// <summary>
/// isOrdered getter
/// For a multivalued multiplicity, this attribute specifies whether the values in
/// an instantiation of this MultiplicityElement are sequentially ordered.
/// </summary>
bool MultiplicityElement::isOrdered() const {
    return isOrdered_;
}

/// <summary>
/// isOrdered setter
/// For a multivalued multiplicity, this attribute specifies whether the values in
/// an instantiation of this MultiplicityElement are sequentially ordered.
/// </summary>
void MultiplicityElement::setIsOrdered(bool value) {
    isOrdered_ = value;
}

/// <summary>
/// isUnique getter
/// For a multivalued multiplicity, this attributes specifies whether the values in
/// an instantiation of this MultiplicityElement are unique.
/// </summary>
bool MultiplicityElement::isUnique() const {
    return isUnique_;
}

/// <summary>
/// isUnique setter
/// For a multivalued multiplicity, this attributes specifies whether the values in
/// an instantiation of this MultiplicityElement are unique.
/// </summary>
void MultiplicityElement::setIsUnique(bool value) {
    isUnique_ = value;
}

/// <summary>
/// lower getter
/// The lower bound of the multiplicity interval.
/// </summary>
int MultiplicityElement::lower() const {
    return lower_;
}

/// <summary>
/// lower setter
/// The lower bound of the multiplicity interval.
/// </summary>
void MultiplicityElement::setLower(int value) {
    lower_ = value;
}

/// <summary>
/// lowerValue getter
/// The specification of the lower bound for this multiplicity.
/// </summary>
shared_ptr<ValueSpecification> MultiplicityElement::lowerValue() const {
    return lowerValue_;
}

/// <summary>
/// lowerValue setter
/// The specification of the lower bound for this multiplicity.
/// </summary>
void MultiplicityElement::setLowerValue(shared_ptr<ValueSpecification> value) {
    lowerValue_ = value;
}

/// <summary>
/// upper getter
/// The upper bound of the multiplicity interval.
/// </summary>
int MultiplicityElement::upper() const {
    return upper_;
}

/// <summary>
/// upper setter
/// The upper bound of the multiplicity interval.
/// </summary>
void MultiplicityElement::setUpper(int value) {
    upper_ = value;
}

/// <summary>
/// upperValue getter
/// The specification of the upper bound for this multiplicity.
/// </summary>
shared_ptr<ValueSpecification> MultiplicityElement::upperValue() const {
    return upperValue_;
}

/// <summary>
/// upperValue setter
/// The specification of the upper bound for this multiplicity.
/// </summary>
void MultiplicityElement::setUpperValue(shared_ptr<ValueSpecification> value) {
    upperValue_ = value;
}

} // namespace uml
